﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevExpress.XtraEditors.Repository;
using System.Collections;
using ACIT.Util.PowerReflection;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraTreeList;
using DevExpress.XtraTreeList.Columns;
using DevExpress.XtraTreeList.Nodes;
using System.Windows.Forms;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.Utils;

namespace UIShare
{
    public static class ControlExtensions
    {
        #region RepositoryItemComboBox

        public static void BindingData(this RepositoryItemComboBox exTarget, IEnumerable dataSource)//, string displayMember, string valueMember)
        {
            exTarget.Items.Clear();

            if (dataSource == null)
                return;

            foreach (var item in dataSource)
            {
                exTarget.Items.Add(item);
            }
        }

        #endregion

        #region RepositoryItemCheckedComboBoxEdit

        public static void BindingData(this RepositoryItemCheckedComboBoxEdit exTarget, IEnumerable dataSource)
        {
            BindingData<object>(exTarget, dataSource, null);
        }

        public static void BindingData<T>(this RepositoryItemCheckedComboBoxEdit exTarget, IEnumerable dataSource, Func<T, bool> compareItem)
        {
            exTarget.Items.Clear();

            if (dataSource == null)
                return;

            foreach (var item in dataSource)
            {
                if (compareItem != null)
                    exTarget.Items.Add(item, compareItem.Invoke((T)item));
                else
                    exTarget.Items.Add(item);
            }
        }

        public static List<T> GetCheckedItems<T>(this RepositoryItemCheckedComboBoxEdit exTarget)
        {
            List<T> result = new List<T>();

            foreach (var item in exTarget.Items)
            {
                if (((CheckedListBoxItem)item).CheckState == CheckState.Checked)
                    result.Add((T)((CheckedListBoxItem)item).Value);
            }

            return result;
        }

        public static void SetCheckedItems<T>(this RepositoryItemCheckedComboBoxEdit exTarget, IEnumerable checkedItems, Func<T, bool> compareItem)
        {
            foreach (var item in exTarget.Items)
            {
                if (compareItem != null)
                {
                    bool isContains = compareItem.Invoke((T)((CheckedListBoxItem)item).Value);
                    if (isContains)
                        ((CheckedListBoxItem)item).CheckState = CheckState.Checked;
                    else
                        ((CheckedListBoxItem)item).CheckState = CheckState.Unchecked;
                }
            }
        }

        #endregion

        #region ComboBoxEdit
        public static object GetValue(this ComboBoxEdit exTarget)
        {
            return GetValue(exTarget, null);
        }

        public static object GetValue(this ComboBoxEdit exTarget, string valueMember)
        {
            return GetValue<object>(exTarget, valueMember);
        }

        public static T GetValue<T>(this ComboBoxEdit exTarget)
        {
            return GetValue<T>(exTarget, null);
        }

        public static T GetValue<T>(this ComboBoxEdit exTarget, string valueMember)
        {
            if (exTarget.SelectedIndex == -1)
                return default(T);

            object selectedItem = exTarget.SelectedItem;

            if (!string.IsNullOrEmpty(valueMember))
                return (T)ReflectionUtilities.GetPropertyInfo(selectedItem.GetType(), valueMember).GetValue(selectedItem, null);
            else
                return (T)selectedItem;
        }

        public static void SetValue<T>(this ComboBoxEdit exTarget, T value)
        {
            SetValue<T>(exTarget, value, null);
        }

        public static void SetValue<T>(this ComboBoxEdit exTarget, T value, string valueMember)
        {
            setDisplayOrValue(exTarget, value,
                    (i, v) =>
                    {
                        object itemValue = i;
                        if (!string.IsNullOrEmpty(valueMember))
                            itemValue = ReflectionUtilities.GetPropertyInfo(i.GetType(), valueMember).GetValue(i, null);
                        return itemValue == v || object.Equals(itemValue, v) || object.ReferenceEquals(itemValue, v);
                    }
                );
        }

        public static string GetDisplay(this ComboBoxEdit exTarget)
        {
            return GetDisplay(exTarget, null);
        }

        public static string GetDisplay(this ComboBoxEdit exTarget, string displayMember)
        {
            object result = GetDisplay<object>(exTarget, displayMember);

            if (result == null)
                return string.Empty;
            else
                return result.ToString();
        }

        public static T GetDisplay<T>(this ComboBoxEdit exTarget)
        {
            return GetDisplay<T>(exTarget, null);
        }

        public static T GetDisplay<T>(this ComboBoxEdit exTarget, string displayMember)
        {
            if (exTarget.SelectedIndex == -1)
                return default(T);

            object selectedItem = exTarget.SelectedItem;

            if (!string.IsNullOrEmpty(displayMember))
                return (T)ReflectionUtilities.GetPropertyInfo(selectedItem.GetType(), displayMember).GetValue(selectedItem, null);
            else
                return (T)selectedItem;
        }

        public static void SetDisplay(this ComboBoxEdit exTarget, object value)
        {
            SetDisplay(exTarget, value, null);
        }

        public static void SetDisplay(this ComboBoxEdit exTarget, object value, string displayMember)
        {
            setDisplayOrValue(exTarget, value,
                    (i, v) =>
                    {
                        object itemValue = i;
                        if (!string.IsNullOrEmpty(displayMember))
                            itemValue = ReflectionUtilities.GetPropertyInfo(i.GetType(), displayMember).GetValue(i, null);
                        return itemValue == v || object.Equals(itemValue, v) || object.ReferenceEquals(itemValue, v);
                    }
                );
        }

        private static void setDisplayOrValue(ComboBoxEdit comboBoxEdit, object value, Func<object, object, bool> equalsItemFunc)
        {
            foreach (object item in comboBoxEdit.Properties.Items)
            {
                bool isEquals = equalsItemFunc.Invoke(item, value);

                if (isEquals)
                {
                    comboBoxEdit.SelectedItem = item;
                    return;
                }
            }

            comboBoxEdit.SelectedIndex = -1;
        }


        public static void ReadOnly(this ComboBoxEdit exTarget, bool readOnly)
        {
            exTarget.TabStop = !readOnly;
            exTarget.Properties.ReadOnly = readOnly;
            exTarget.Properties.BorderStyle = readOnly ? BorderStyles.NoBorder : BorderStyles.Default;
            if (exTarget.Properties.Buttons.Count > exTarget.Properties.ActionButtonIndex)
                exTarget.Properties.Buttons[exTarget.Properties.ActionButtonIndex].Visible = !readOnly;
        }
        #endregion

        #region ItemCheckedComboBoxEdit
        public static void ReadOnly(this CheckedComboBoxEdit exTarget, bool readOnly)
        {
            exTarget.TabStop = !readOnly;
            exTarget.Properties.ReadOnly = readOnly;
            exTarget.Properties.BorderStyle = readOnly ? BorderStyles.NoBorder : BorderStyles.Default;
            if (exTarget.Properties.Buttons.Count > exTarget.Properties.ActionButtonIndex)
                exTarget.Properties.Buttons[exTarget.Properties.ActionButtonIndex].Visible = !readOnly;
        }
        #endregion

        #region TextEdit
        public static string GetText(this TextEdit exTarget)
        {
            return exTarget.Text.Trim();
        }

        public static void SetText(this TextEdit exTarget, string text)
        {
            exTarget.Text = text;
        }

        public static void SetText(this TextEdit exTarget, object text)
        {
            if (text == null)
            {
                exTarget.Text = string.Empty;
                return;
            }

            decimal value;
            if (decimal.TryParse(text.ToString(),out value))
            {
                exTarget.Text = value.ToString("0.##");
                return;
            }

            exTarget.Text = text.ToString();
        }

        public static void ReadOnly(this TextEdit exTarget, bool readOnly)
        {
            exTarget.TabStop = !readOnly;
            exTarget.Properties.ReadOnly = readOnly;
            exTarget.Properties.BorderStyle = readOnly ? BorderStyles.NoBorder : BorderStyles.Default;
        }
        #endregion

        #region SpinEdit
        public static decimal GetValue(this SpinEdit exTarget)
        {
            return GetValue(exTarget, false).Value;
        }

        public static decimal? GetValue(this SpinEdit exTarget, bool allowNull)
        {
            if ((exTarget.EditValue == null || exTarget.EditValue == string.Empty) && allowNull)
                return null;
            else if ((exTarget.EditValue == null || exTarget.EditValue == string.Empty) && !allowNull)
                return 0;
            else
                return exTarget.Value;
        }

        public static void SetValue(this SpinEdit exTarget, decimal value)
        {
            exTarget.Value = value;
        }

        public static void SetValue(this SpinEdit exTarget, decimal? value)
        {
            if (!value.HasValue)
            {
                exTarget.Properties.AllowNullInput = DefaultBoolean.True;
                exTarget.EditValue = null;
            }
            else
            {
                exTarget.Value = value.Value;
            }
        }

        public static void ReadOnly(this SpinEdit exTarget, bool readOnly)
        {
            exTarget.TabStop = !readOnly;
            exTarget.Properties.ReadOnly = readOnly;
            exTarget.Properties.BorderStyle = readOnly ? BorderStyles.NoBorder : BorderStyles.Default;
            if (exTarget.Properties.Buttons.Count > exTarget.Properties.SpinButtonIndex)
                exTarget.Properties.Buttons[exTarget.Properties.SpinButtonIndex].Visible = !readOnly;
        }
        #endregion

        #region DateEdit

        public static DateTime? GetValue(this DateEdit exTarget)
        {
            if (exTarget.EditValue == null || exTarget.EditValue == string.Empty)
                return null;

            return exTarget.DateTime;
        }

        public static DateTime GetValue(this DateEdit exTarget, DateTime defaultValue)
        {
            if (exTarget.EditValue == null || exTarget.EditValue == string.Empty)
                return defaultValue;
            return exTarget.DateTime;
        }

        public static void SetValue(this DateEdit exTarget, DateTime? value)
        {
            if (value.HasValue)
                exTarget.EditValue = value.Value;
            else
                exTarget.EditValue = null;
        }

        public static void ReadOnly(this DateEdit exTarget, bool readOnly)
        {
            exTarget.TabStop = !readOnly;
            exTarget.Properties.ReadOnly = readOnly;
            exTarget.Properties.BorderStyle = readOnly ? BorderStyles.NoBorder : BorderStyles.Default;
            if (exTarget.Properties.Buttons.Count > exTarget.Properties.ActionButtonIndex)
                exTarget.Properties.Buttons[exTarget.Properties.ActionButtonIndex].Visible = !readOnly;
        }
        #endregion

        #region CheckEdit
        public static bool GetValue(this CheckEdit exTarget)
        {
            return exTarget.Checked;
        }

        public static void SetValue(this CheckEdit exTarget, bool value)
        {
            exTarget.Checked = value;
        }

        public static void ReadOnly(this CheckEdit exTarget, bool readOnly)
        {
            exTarget.TabStop = !readOnly;
            exTarget.Properties.ReadOnly = readOnly;
        }
        #endregion

        #region MemoEdit
        public static void ReadOnly(this MemoEdit exTarget, bool readOnly)
        {
            exTarget.TabStop = !readOnly;
            exTarget.Properties.ReadOnly = readOnly;
        }
        #endregion

        #region BaseEdit
        public static void ClearValue(this BaseEdit exTarget)
        {
            exTarget.EditValue = null;
        }

        public static void ClearValue(params BaseEdit[] baseEdits)
        {
            foreach (var baseEdit in baseEdits)
            {
                baseEdit.ClearValue();
            }
        }
        #endregion

        #region TreeList

        //public static void BindingData(this TreeList exTarget, IEnumerable dataSource, string displayMember, string valueMember, string idMember, string parentIdMember)
        //{
        //    exTarget.Nodes.Clear();

        //    if (dataSource == null)
        //        return;

        //    exTarget.BeginUpdate();

        //    #region 创建column
        //    exTarget.Columns.Clear();
        //    exTarget.Columns.AddField(displayMember);
        //    #endregion

        //    #region 创建treeListItems
        //    Dictionary<object, TreeListItem> treeListNodeItems = new Dictionary<object, TreeListItem>();

        //    foreach (var item in dataSource)
        //    {
        //        object id = null;
        //        object parentId = null;
        //        object display = item;
        //        object value = item;

        //        Type itemType = item.GetType();

        //        if (!string.IsNullOrEmpty(idMember))
        //        {
        //            id = ReflectionUtilities.GetPropertyInfo(itemType, idMember).GetValue(item, null);
        //        }

        //        if (!string.IsNullOrEmpty(parentIdMember))
        //        {
        //            parentId = ReflectionUtilities.GetPropertyInfo(itemType, parentIdMember).GetValue(item, null);
        //        }

        //        if (!string.IsNullOrEmpty(displayMember))
        //        {
        //            display = ReflectionUtilities.GetPropertyInfo(itemType, displayMember).GetValue(item, null);
        //        }

        //        if (!string.IsNullOrEmpty(valueMember))
        //        {
        //            value = ReflectionUtilities.GetPropertyInfo(itemType, valueMember).GetValue(item, null);
        //        }

        //        TreeListItem treeListItem = new TreeListItem()
        //        {
        //            Id = id,
        //            ParentId = parentId,
        //            Display = new object[] { display },
        //            Value = value
        //        };

        //        treeListNodeItems.Add(treeListItem.Id, treeListItem);
        //    }
        //    #endregion

        //    #region 添加nodes到treeList中

        //    Hashtable treeNodes = new Hashtable();
        //    int index = 0;
        //    while (index != treeListNodeItems.Count)
        //    {
        //        foreach (TreeListItem nodeItem in treeListNodeItems.Values)
        //        {
        //            if (treeNodes.ContainsKey(nodeItem.Id)) { continue; }

        //            TreeListNode treeNode = null;

        //            //如果自己是沒有父親的
        //            if (nodeItem.ParentId == null || !treeListNodeItems.ContainsKey(nodeItem.ParentId))
        //            {
        //                //添加自己進TreeList
        //                treeNode = exTarget.AppendNode(nodeItem.Value, null, nodeItem);
        //            }
        //            //如果自己是有父親的,而且父親已經在TreeList中的
        //            else if (treeListNodeItems.ContainsKey(nodeItem.ParentId) && treeNodes.ContainsKey(nodeItem.ParentId))
        //            {
        //                //添加自己進TreeList
        //                treeNode = exTarget.AppendNode(nodeItem.Value, (TreeListNode)treeNodes[nodeItem.ParentId], nodeItem);
        //            }

        //            if (treeNode != null)
        //            {
        //                treeNodes.Add(nodeItem.Id, treeNode);
        //                index++;
        //            }
        //        }
        //    }
        //    #endregion

        //    exTarget.EndUpdate();
        //}

        //#region TreeListItem
        //class TreeListItem
        //{
        //    public object[] Display { get; set; }
        //    public object Value { get; set; }
        //    public object Id { get; set; }
        //    public object ParentId { get; set; }
        //    public override string ToString()
        //    {
        //        if (Display != null && Display.Length > 0)
        //        {
        //            return Display[0].ToString();
        //        }

        //        return Value.ToString();
        //    }
        //}
        //#endregion

        #endregion

        #region BindingSource
        public static void BindingData(this BindingSource bindingSource, object dataSource)
        {
            bindingSource.DataSource = null;

            if (dataSource == null)
                return;

            bindingSource.DataSource = dataSource;
        }
        #endregion

        #region GridView
        public static void CustomDrawCell<T>(this GridView exTarget, RowCellCustomDrawEventArgs drawEventArgs, Func<T, bool> matchConditionAction, Action drawAction)
        {
            object rowData = exTarget.GetRow(drawEventArgs.RowHandle);

            if (rowData == null || !(rowData is T))
                return;

            bool actionResult = matchConditionAction.Invoke((T)rowData);

            if (actionResult)
                drawAction.Invoke();
        }
        #endregion

        #region GridLookupEdit
        public static void SetValue(this GridLookUpEdit exTarget, object value)
        {
            SetValue<object>(exTarget, value);
        }

        public static void SetValue<T>(this GridLookUpEdit exTarget, T value)
        {
            exTarget.EditValue = value;
        }

        public static object GetValue(this GridLookUpEdit exTarget)
        {
            return GetValue<object>(exTarget);
        }

        public static T GetValue<T>(this GridLookUpEdit exTarget)
        {
            if (exTarget.EditValue == null)
                return default(T);

            return (T)exTarget.EditValue;
        }

        public static void ReadOnly(this GridLookUpEdit exTarget, bool readOnly)
        {
            exTarget.TabStop = !readOnly;
            exTarget.Properties.ReadOnly = readOnly;
            exTarget.Properties.BorderStyle = readOnly ? BorderStyles.NoBorder : BorderStyles.Default;
            if (exTarget.Properties.Buttons.Count > exTarget.Properties.ActionButtonIndex)
                exTarget.Properties.Buttons[exTarget.Properties.ActionButtonIndex].Visible = !readOnly;
        }
        #endregion
    }
}
